在 RT-Thread 中,有一个打印函数 rt_kprintf() 供用户使用,方便在调试的时候输出各种信息。如果 要想使用 rt_kprintf(),则必须将控制台重映射到 rt_kprintf(),这个控制台可以是串口、CAN、USB、 以太网等输出设备,用的最多的就是串口,接下来我们讲解下如何将串口重定向到 rt_kprintf()。[参考野火F103]
添加bsp_usart.c, bsp_usart.h
bsp_usart.c
#include "bsp_usart.h"
/**
* @brief 配置嵌套向量中断控制器NVIC
* @param 无
* @retval 无
*/
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* 抢断优先级*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief USART GPIO 配置,工作参数配置
* @param 无
* @retval 无
*/
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 打开串口GPIO的时钟
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
// 打开串口外设的时钟
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
// 将USART Tx的GPIO配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
// 将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
// 配置串口的工作参数
// 配置波特率
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
// 配置 针数据字长
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 配置停止位
USART_InitStructure.USART_StopBits = USART_StopBits_1;
// 配置校验位
USART_InitStructure.USART_Parity = USART_Parity_No ;
// 配置硬件流控制
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
// 配置工作模式,收发一起
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
// 完成串口的初始化配置
USART_Init(DEBUG_USARTx, &USART_InitStructure);
// 串口中断优先级配置
NVIC_Configuration();
// 使能串口接收中断
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
// 使能串口
USART_Cmd(DEBUG_USARTx, ENABLE);
}
/***************** 发送一个字节 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);
/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/****************** 发送8位的数组 ************************/
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
uint8_t i;
for(i=0; i<num; i++)
{
/* 发送一个字节数据到USART */
Usart_SendByte(pUSARTx,array[i]);
}
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}
/***************** 发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do
{
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while(*(str + k)!='\0');
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
{}
}
/***************** 发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;
/* 取出高八位 */
temp_h = (ch&0XFF00)>>8;
/* 取出低八位 */
temp_l = ch&0XFF;
/* 发送高八位 */
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
/* 发送低八位 */
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口 */
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
bsp_usart.h
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include <stdio.h>
/**
* 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
* 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
* 2-修改GPIO的宏
*/
// 串口1-USART1
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_IRQ USART1_IRQn
#define DEBUG_USART_IRQHandler USART1_IRQHandler
// 串口2-USART2
//#define DEBUG_USARTx USART2
//#define DEBUG_USART_CLK RCC_APB1Periph_USART2
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
//// USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOA
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2
//#define DEBUG_USART_RX_GPIO_PORT GPIOA
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3
//#define DEBUG_USART_IRQ USART2_IRQn
//#define DEBUG_USART_IRQHandler USART2_IRQHandler
// 串口3-USART3
//#define DEBUG_USARTx USART3
//#define DEBUG_USART_CLK RCC_APB1Periph_USART3
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
//// USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOB)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOB
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
//#define DEBUG_USART_RX_GPIO_PORT GPIOB
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
//#define DEBUG_USART_IRQ USART3_IRQn
//#define DEBUG_USART_IRQHandler USART3_IRQHandler
// 串口4-UART4
//#define DEBUG_USARTx UART4
//#define DEBUG_USART_CLK RCC_APB1Periph_UART4
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
//// USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOC
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
//#define DEBUG_USART_RX_GPIO_PORT GPIOC
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
//#define DEBUG_USART_IRQ UART4_IRQn
//#define DEBUG_USART_IRQHandler UART4_IRQHandler
// 串口5-UART5
//#define DEBUG_USARTx UART5
//#define DEBUG_USART_CLK RCC_APB1Periph_UART5
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
//// USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOC
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12
//#define DEBUG_USART_RX_GPIO_PORT GPIOD
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2
//#define DEBUG_USART_IRQ UART5_IRQn
//#define DEBUG_USART_IRQHandler UART5_IRQHandler
void USART_Config(void);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);
#endif /* __USART_H */重构void rt_hw_console_output(const char *str)函数
board.c
/*
* File : board.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2017-07-24 Tanek the first version
*/
#include "board.h"
#include <rthw.h>
#include <rtthread.h>
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE 1024
static uint32_t rt_heap[RT_HEAP_SIZE]; // heap default size: 4K(1024 * 4)
RT_WEAK void *rt_heap_begin_get(void)
{
return rt_heap;
}
RT_WEAK void *rt_heap_end_get(void)
{
return rt_heap + RT_HEAP_SIZE;
}
#endif
/**
* This function will initial your board.
*/
void rt_hw_board_init()
{
/* 初始化 SysTick */
SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
/* 初始化开发板的 LED */
LED_GPIO_Config();
// 初始化串口
USART_Config();
/* 初始化测试部分, 测试完把代码删除*/
// LED2_ON;
// while (1)
// {
// /* code */
// }
/* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}
void SysTick_Handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
rt_tick_increase();
/* leave interrupt */
rt_interrupt_leave();
}
/**************************重写rtthread控制台输出, 通过串口发送*************************************/
void rt_hw_console_output(const char *str)
{
/*进入临界区*/
rt_enter_critical();
/* 直到将字符串发送完 */
while (*str != '\0')
{
/* 换行 */
if (*str == '\n')
{
USART_SendData(DEBUG_USARTx, '\r');
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
}
USART_SendData(DEBUG_USARTx, *str++);
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
}
/* 退出临界区 */
rt_exit_critical();
}
初始化串口配置
board.c
USART_Config();调用
mian.c
/**
*********************************************************************
* @file main.c
* @author fire
* @version V1.0
* @date 2018-xx-xx
* @brief RT-Thread 3.0 + STM32 工程模版
*********************************************************************
* @attention
*
* 实验平台:野火 F103-指南者 STM32 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :https://fire-stm32.taobao.com
*
**********************************************************************
*/
/*
*************************************************************************
* 包含的头文件
*************************************************************************
*/
#include "board.h"
#include "rtthread.h"
/*
*************************************************************************
* 变量
*************************************************************************
*/
/* 定义线程控制块 */
//static struct rt_thread led1_thread;
static rt_thread_t led1_thread = RT_NULL;
static rt_thread_t led2_thread = RT_NULL;
/******************************static memory*******************************/
/* 定义线程控制块 */
// static struct rt_thread led1_thread;
/* 定义线程控栈时要求 RT_ALIGN_SIZE 个字节对齐 */
// ALIGN(RT_ALIGN_SIZE)
/* 定义线程栈 */
// static rt_uint8_t rt_led1_thread_stack[1024];
/****************************static memory end*****************************/
/*
*************************************************************************
* 函数声明
*************************************************************************
*/
static void led1_thread_entry(void *parameter);
static void led2_thread_entry(void *parameter);
/*
*************************************************************************
* main 函数
*************************************************************************
*/
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
/* 暂时没有在main线程里面创建任务应用线程 */
// thread 1
led1_thread = rt_thread_create("led1",led1_thread_entry,RT_NULL,512, 3,20);
/* 线程启动,进行调度 */
if (led1_thread != RT_NULL)
rt_thread_startup(led1_thread);
else
return -1;
// thread 2
led2_thread = rt_thread_create("led2", led2_thread_entry, RT_NULL, 512, 3, 20);
if (led2_thread != RT_NULL)
rt_thread_startup(led2_thread);
else
return -1;
/**********************************static memory demo ***************************************/
// rt_thread_init(&led1_thread, /* 线程控制块 */
// "led1", /* 线程名字 */
// led1_thread_entry, /* 线程入口函数 */
// RT_NULL, /* 线程入口函数参数 */
// &rt_led1_thread_stack[0], /* 线程栈起始地址 */
// sizeof(rt_led1_thread_stack), /* 线程栈大小 */
// 3, /* 线程的优先级 */
// 20); /* 线程时间片 */
// rt_thread_startup(&led1_thread); /* 启动线程,开启调度 */
/******************************static memory demo end*************************************/
}
/*
*************************************************************************
* 线程定义
*************************************************************************
*/
static void led1_thread_entry(void *parameter){
while (1)
{
LED1_ON;
rt_thread_delay(1500); /* 延时 500 个 tick */
LED1_OFF;
rt_thread_delay(1500); /* 延时 500 个 tick */
rt_kprintf("thread --[1], Red\r\n");
}
}
static void led2_thread_entry(void *parameter)
{
while (1)
{
LED2_ON;
rt_thread_delay(500); /* 延时 500 个 tick */
LED2_OFF;
rt_thread_delay(500); /* 延时 500 个 tick */
rt_kprintf("thread --[2], Green\r\n");
}
}